﻿using System;
using System.Collections.Generic;
using System.Web;
using System.Text.RegularExpressions;
using System.Collections;
namespace Common
{
    /// <summary>
    ///验证器
    /// </summary>
    public class Validator
    {
        /// <summary>
        /// 验证器状态
        /// </summary>
        bool Status = true;
        /// <summary>
        /// 验证项集合
        /// </summary>
        public List<Item> Items = new List<Item>();
        /// <summary>
        /// 是否全部验证
        /// </summary>
        bool Gamut = Common.TypeParse.StrToBool(Common.RequestHelper.GetString("Gamut"), false);
        /// <summary>
        /// 验证项结果集合
        /// </summary>
        Hashtable ItemsResult = new Hashtable();

        /// <summary>
        /// 是否存在验证项
        /// </summary>
        /// <param name="name">验证项名称</param>
        /// <returns></returns>
        bool ExistItem(string name)
        {
            if (HttpContext.Current.Request[name] != null)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 验证委托
        /// </summary>
        public delegate bool DValidate(string value);

        /// <summary>
        /// 设置验证项
        /// </summary>
        /// <param name="name"></param>
        /// <param name="status"></param>
        /// <param name="msg"></param>
        /// <param name="key"></param>
        void SetResult(string name, bool status, string msg = null, string key = null)
        {
            ItemsResult[name] = new { status = status, msg = msg, key = key };
            Status &= status;
        }

        /// <summary>
        /// 处理验证方法并返回结果
        /// </summary>
        public Hashtable Validate()
        {
            if (OnStart != null) OnStart.Invoke();
            foreach (var item in Items)
            {
                if (Gamut || ExistItem(item.name))
                {
                    string value = item.value;
                    #region 检查是否必填
                    if (item.status && item.rule.required && string.IsNullOrEmpty(value))
                    {
                        item.setResult(false, null, "required");
                    }
                    #endregion
                    #region 检查类型
                    if (item.status && !string.IsNullOrEmpty(value))
                    {
                        string regex = string.Empty;
                        switch (item.rule.type)
                        {
                            case RuleType.email:
                                regex = @"^\w+@(\w+.)+[a-z0-9_\-]+$"; break;
                            case RuleType._int:
                                regex = @"^\d+$"; break;
                            case RuleType._float:
                                regex = @"^\d+\.?\d*$"; break;
                            case RuleType.chinese:
                                regex = @"^[\u4e00-\u9fa5]+$"; break;
                            case RuleType.english:
                                regex = @"^[a-zA-Z\-\s]+$"; break;
                            case RuleType.url:
                                regex = @"^(file|gopher|news|nntp|telnet|http|ftp|https|ftps|sftp):\/\/[^\s]*$"; break;
                            case RuleType.mobile:
                                regex = @"^(13|15|18)\d{9}$"; break;
                            case RuleType.tel:
                                regex = @"^((\d{3}-)?\d{8})|((\d{4}-)?\d{7})$"; break;
                            case RuleType.phone:
                                regex = @"^(((13|15|18)\d{9})|(((\d{3}-)?\d{8})|((\d{4}-)?\d{7})))$"; break;
                            case RuleType.qq:
                                regex = @"^(([1-9][0-9]{4,})|(\w+@(\w+.)+[a-z0-9_\-]+))$"; break;
                            case RuleType.zip:
                                regex = @"^[1-9]\d{5}(?!\d)$"; break;
                            case RuleType.idcard:
                                regex = @"^(\d{17}|\d{14})(\d|x)$"; break;
                            case RuleType.ip:
                                regex = @"^((?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d))$"; break;
                            case RuleType.date:
                                regex = @"^(?=\d)(?:(?!(?:1582(?:\.|-|\/)10(?:\.|-|\/)(?:0?[5-9]|1[0-4]))|(?:1752(?:\.|-|\/)0?9(?:\.|-|\/)(?:0?[3-9]|1[0-3])))(?=(?:(?!000[04]|(?:(?:1[^0-6]|[2468][^048]|[3579][^26])00))(?:(?:\d\d)(?:[02468][048]|[13579][26]))\D0?2\D29)|(?:\d{4}\D(?!(?:0?[2469]|11)\D31)(?!0?2(?:\.|-|\/)(?:29|30))))(\d{4})([-\/.])(0?\d|1[012])\2((?!00)[012]?\d|3[01])(?:$|(?=\x20\d)\x20))?((?:(?:0?[1-9]|1[012])(?::[0-5]\d){0,2}(?:\x20[aApP][mM]))|(?:[01]\d|2[0-3])(?::[0-5]\d){1,2})?$"; break;
                        }
                        if (!string.IsNullOrEmpty(regex) && !new Regex(regex, RegexOptions.IgnoreCase).IsMatch(value))
                        {
                            item.setResult(false, null, "type");
                        };
                    }
                    #endregion
                    #region 检查正则
                    if (item.status
                        && !string.IsNullOrEmpty(item.rule.regex)
                        && !string.IsNullOrEmpty(value)
                        && !new Regex(item.rule.regex, RegexOptions.IgnoreCase).IsMatch(value))
                    {
                        item.setResult(false, null, "regex");
                    };
                    #endregion
                    #region 自定义检查
                    foreach (var custom in item.rule.customs)
                    {
                        item.status &= custom.validate(item.value);
                        if (!item.status)
                        {
                            item.setResult(item.status, custom.msg, custom.key);
                            break;
                        }
                    }
                    #endregion
                    #region 最小长度
                    if (item.status && item.rule.minLength.HasValue && !string.IsNullOrEmpty(value))
                    {
                        if (value.Length < item.rule.minLength)
                        {
                            item.setResult(false, null, "minLength");
                        };
                    };
                    #endregion
                    #region 最大长度
                    if (item.status && item.rule.maxLength.HasValue && !string.IsNullOrEmpty(value))
                    {
                        if (value.Length > item.rule.maxLength)
                        {
                            item.setResult(false, null, "maxLength");
                        };
                    };
                    #endregion
                    SetResult(item.name, item.status, item.msg, item.key);
                }
            }
            if (Gamut)
            {
                if (Status)
                {
                    if (OnSuccess != null) OnSuccess.Invoke();
                }
                else
                {
                    if (OnFail != null) OnFail.Invoke();
                }
            }
            if (OnEnd != null) OnEnd.Invoke();
            return ItemsResult;
        }
        public delegate void ValidatorHandler();
        /// <summary>
        /// 验证成功事件
        /// </summary>
        public event ValidatorHandler OnSuccess;
        /// <summary>
        /// 验证失败事件
        /// </summary>
        public event ValidatorHandler OnFail;
        /// <summary>
        /// 验证开始事件
        /// </summary>
        public event ValidatorHandler OnStart;
        /// <summary>
        /// 验证结束事件
        /// </summary>
        public event ValidatorHandler OnEnd;

        /// <summary>
        /// 自定义验证方法
        /// </summary>
        public class Custom
        {
            /// <summary>
            /// 失败的提示信息
            /// </summary>
            public string msg { get; set; }
            /// <summary>
            /// 失败的提示信息键
            /// </summary>
            public string key { get; set; }
            /// <summary>
            /// 验证方法的委托
            /// </summary>
            public Validator.DValidate validate;
        }
        /// <summary>
        /// 验证项
        /// </summary>
        public class Item
        {
            /// <summary>
            /// 名称
            /// </summary>
            public string name { get; set; }
            /// <summary>
            /// 值
            /// </summary>
            public string value { get; set; }
            /// <summary>
            /// 状态
            /// </summary>
            public bool status = true;
            /// <summary>
            /// 提示信息(默认为成功时的信息，如果失败了会覆盖此信息)
            /// </summary>
            public string msg { get; set; }
            /// <summary>
            /// 提示信息键(默认为成功时的键，如果失败了会覆盖此键)
            /// </summary>
            public string key { get; set; }
            /// <summary>
            /// 验证规则
            /// </summary>
            public Rule rule { get; set; }
            /// <summary>
            /// 设置验证结果
            /// </summary>
            /// <param name="status">结果</param>
            /// <param name="msg">提示信息</param>
            /// <param name="key">提示信息键</param>
            public void setResult(bool status, string msg = null, string key = null)
            {
                this.status = status;
                this.msg = msg;
                this.key = key;
            }
        }
        /// <summary>
        /// 验证规则
        /// </summary>
        public class Rule
        {
            public bool required;
            public RuleType? type;
            public string regex;
            public int? minLength;
            public int? maxLength;
            public List<Custom> customs = new List<Custom>();
        }
        /// <summary>
        /// 验证类型
        /// </summary>
        public enum RuleType
        {
            email,
            _int,
            _float,
            chinese,
            english,
            url,
            /// <summary>
            /// 手机
            /// </summary>
            mobile,
            /// <summary>
            /// 座机
            /// </summary>
            tel,
            /// <summary>
            /// 手机或者座机
            /// </summary>
            phone,
            qq,
            zip,
            idcard,
            ip,
            date
        }
    }
}
